package com.ymx.darling.wrapper.fragment;

import com.ymx.darling.bean.entity.BeanInfo;
import com.ymx.darling.bean.entity.BeanInfoManager;
import com.ymx.darling.bean.entity.FieldInfo;
import com.ymx.darling.bean.sql.BoundSql;
import com.ymx.darling.bean.sql.SqlParsingHelper;
import com.ymx.darling.util.StringUtil;
import com.ymx.darling.bean.sql.SqlStatement;
import com.ymx.darling.wrapper.QueryWrapper;
import com.ymx.darling.wrapper.Wrappers;

import java.util.*;

/**
 * 保存select中的字段
 */
public class SelectSegment implements SqlSegment {
    private final LinkedList<String> columnList = new LinkedList<>();
    private final List<Object> paramList = new ArrayList<>();
    private final QueryWrapper queryWrapper;
    private boolean distinctFlag;

    public SelectSegment(QueryWrapper queryWrapper) {
        this.queryWrapper = queryWrapper;
    }


    @Override
    public SqlStatement getSqlStatement() {
        StringJoiner columnJoiner = new StringJoiner(", ");
        this.renameColumnAs(this.columnList).forEach(columnJoiner::add);
        String columnJoinerString = columnJoiner.toString();
        // 判断添加去重关键字
        if (this.distinctFlag) {
            columnJoinerString = "DISTINCT " + columnJoinerString;
        }
        return new SqlStatement(columnJoinerString, this.paramList);
    }


    /**
     * 返回当前queryWrapper中from 和 join引用的表的数量
     * @return int
     */
    private int getTableCount() {
        return Wrappers.getQueryFroms(queryWrapper).size() + Wrappers.getJoinFroms(queryWrapper).size();
    }


    /**
     * 统计当前queryWrapper中表中字段重名的次数
     * @return map
     */
    private Map<String, Integer> getColumnCountByQueryWrapper() {
        Map<String, Integer> columnCountMap = new HashMap<>();
        Set<String> tables = new HashSet<>();
        tables.addAll(Wrappers.getQueryFroms(queryWrapper));
        tables.addAll(Wrappers.getJoinFroms(queryWrapper));
        tables.forEach(table -> {
            if (BeanInfoManager.hasTable(table)) {
                BeanInfo tableBeanInfo = BeanInfoManager.getTableBeanInfo(table);
                for(FieldInfo fieldInfo : tableBeanInfo.getQueryColumn()) {
                    String colName = fieldInfo.getColumn();
                    columnCountMap.put(colName, columnCountMap.getOrDefault(colName, 0) + 1);
                }
            }
        });
        return columnCountMap;
    }


    /**
     * 判断QueryWrapper构建多个表的连接查询时 将字段重命名为 table$column 的形式
     * @param columnList select字段列表
     * @return list
     */
    private List<String> renameColumnAs(List<String> columnList) {
        // 判断是单表查询直接返回字段
        if (this.getTableCount() <= 1) {
            return columnList;
        // 判断连表查询则处理字段重名情况
        } else {
            Map<String, Integer> cloumnCountMap = this.getColumnCountByQueryWrapper();
            List<String> columnAsList = new ArrayList<>();
            columnList.forEach(column -> {
                // 已经设置别名的字段默认不处理
                if (column.contains(" AS ")) {
                    columnAsList.add(column);
                } else {
                    // 分割表名与字段名 根据 '.' 分割
                    String[] tableAndColumn = StringUtil.splitTableAndColumn(column);
                    if (tableAndColumn.length == 1) {
                        columnAsList.add(tableAndColumn[0]);
                    } else {
                        String table = tableAndColumn[0];
                        String colum = tableAndColumn[1];
                        // 只有当table是一个有效的表名 并且 字段不为 * 号时 才为字段添加AS
                        Integer columnCount = cloumnCountMap.get(colum);
                        if (columnCount != null && BeanInfoManager.hasTable(table) && !colum.equals("*") && columnCount > 1) {
                            columnAsList.add(String.format("%s.%s AS %s$%s", table, colum, table, colum));
                        } else {
                            columnAsList.add(column);
                        }
                    }
                }
            });

            return columnAsList;
        }
    }


    public void select(String... columns) {
        columnList.addAll(Arrays.asList(columns));
    }


    public void selectSegment(String template, Object... param) {
        BoundSql boundSql = SqlParsingHelper.parseSqlTemplate(template, param);
        boundSql.bindSqlParameter();
        this.select(boundSql.getSql());
        this.paramList.addAll(boundSql.getBindParameters());
    }


    public void distinct() {
        this.distinctFlag = true;
    }
}
